/*
 * Copyright 2020-2030 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
package com.gitee.minimalismstyle.fresh.sys.service.impl

import com.gitee.minimalismstyle.fresh.common.core.domain.R
import com.gitee.minimalismstyle.fresh.common.data.redis.RedisUtils
import com.gitee.minimalismstyle.fresh.common.security.util.SecurityContextUtils
import com.gitee.minimalismstyle.fresh.sys.api.model.SysCodeSequence
import com.gitee.minimalismstyle.fresh.sys.api.service.SysCodeService
import com.gitee.minimalismstyle.fresh.sys.dao.SysCodeRuleDao
import com.gitee.minimalismstyle.fresh.sys.dao.SysCodeSequenceDao
import org.beetl.core.BeetlKit
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional


/**
 * 编号业务
 * @author maoxiaodong
 */
@Service
class SysCodeServiceImpl: SysCodeService {

    @Autowired
    private lateinit var sysCodeRuleDao: SysCodeRuleDao
    @Autowired
    private lateinit var sysCodeSequenceDao: SysCodeSequenceDao
    @Autowired
    private lateinit var redisUtils: RedisUtils

    @Transactional
    override fun generate(ruleCode: String): R<String> {
        return this.generate(ruleCode, mutableMapOf<String, Any>())
    }


    @Transactional
    override fun generate(ruleCode: String, params: MutableMap<String, Any>): R<String> {
        val sysCodeRule = sysCodeRuleDao.findByCode(ruleCode)
        val rule: String = sysCodeRule.rule!!
        val numStartIndex = rule.indexOf("#[")
        if(numStartIndex == -1) {
            return R.error("编码规则【$rule】定义错误")
        }
        val numEndIndex = rule.indexOf("]", numStartIndex)

        if(numEndIndex == -1){
            return R.error("编码规则【$rule】定义错误")
        }
        val numRule = rule.substring(numStartIndex, numEndIndex+1)

        val noNumCode = BeetlKit.render(rule, params)
        val user = SecurityContextUtils.user()
        val sequenceCode = if(user == null){
            "${ruleCode}_${noNumCode}"
        }else{
            "${user.tenantId}_${ruleCode}_${noNumCode}"
        }


        var num = 1
        redisUtils.lock(sequenceCode) {
            var sysCodeSequence: SysCodeSequence? = sysCodeSequenceDao.findByCode(sequenceCode)
            if (sysCodeSequence == null) {
                sysCodeSequence = SysCodeSequence()
                sysCodeSequence.code = sequenceCode
                sysCodeSequence.sequence = 1
            } else {
                sysCodeSequence.sequence = sysCodeSequence.sequence!! + 1
            }
            num = sysCodeSequence.sequence!!
            sysCodeSequenceDao.save(sysCodeSequence)
        }
        val numLength = numEndIndex-numStartIndex-2
        val numStr = String.format("%0${numLength}d", num)
        val code = noNumCode.replace(numRule, numStr)
        return R.success(code)
    }

}